<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>TITLE</title>
<script src="./lib/prototype.js" type="text/javascript"></script>
<script src="./lib/scriptaculous.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
// <![CDATA[

function arrayp(x) {
  return (x instanceof Array);
}

function singlep(x) {
  return (x instanceof Array) && (x.length == 1);
}

function nullp(x) {
  return (x instanceof Array) && (x.length == 0);
}

function numberp(x) {
  return (typeof x == 'number');
}

function append(arrofarr) {
  return [].concat.apply([],arrofarr);
}

function solve(problem) {
  do {
    var flag = false;
    problem.each(function(x,i) {
      if (arrayp(x)) {
	var res = [].without.apply([1,2,3,4,5,6,7,8,9],
				   [].concat(getRow(i), getCol(i), getBox(i)).map(function(x) {
				     return problem[x]}).select(numberp));
	if (singlep(res)) {
	  flag = true;
	  problem[i] = res[0];
	} else {
	  problem[i] = res;
	};
      }
    });
  } while (flag);
  if (problem.any(nullp))
    return [];
  if (problem.all(numberp))
    return [problem];
  var i = 0;
  for(; i < problem.length; i++)
    if (arrayp(problem[i])) break;
  return append(problem[i].map(function(x) {
    var a = problem.toArray();
    a[i] = x;
    return a;}).map(solve));
}

function getRow(p) {
  var row = Math.floor(p / 9) * 9;
  var col = p % 9;
  var r = $R(0,9,true);
  return r.map(function(x) {
    return x + row});
}

function getCol(p) {
  var row = Math.floor(p / 9) * 9;
  var col = p % 9;
  var r = $R(0,9,true);
  return r.map(function(x) {
    return x * 9 + col});
}

function getBox(p) {
  var br = Math.floor(Math.floor(Math.floor(p / 9) * 9) / 27) * 27;
  var bc = Math.floor((p % 9) / 3) * 3;
  var r = [0,1,2,9,10,11,18,19,20];
  return r.map(function(x) {
    return x + br + bc});
}

function button_click() {
  var query = Form.serialize('form0').toQueryParams();
  var problem = $A($R(0,81,true)).map(function(x) {
    var v = parseInt(query[x],10);
    if (isNaN(v) || v <= 0 || v > 9)
      return [1,2,3,4,5,6,7,8,9];
    return v;
  });
  var e = $('main');
  while (e.firstChild) e.removeChild(e.firstChild);
  solve(problem).each(function(pro) {
    e.appendChild(DIV([pro.inGroupsOf(9).map(function(x) {return P(x)}),
		       HR()]))});
}

function main() {
  var problem =
    ['','',7,1,'','','','',3,
     '','',5,'','',7,'',2,'',
     6,'','',9,8,'',4,7,'',
     1,8,'','','',9,'','',7,
     5,'','',6,'','','','',1,
     7,'','','',3,'','',9,8,
     '',7,1,'',2,6,'','',4,
     '',6,'',8,'','',7,'','',
     3,'','','','',4,6,'',2];
  Builder.dump();
  $('inputproblem').appendChild(FORM({id: 'form0'},[
	problem.inGroupsOf(9).map(function(x,i) {
	  return [x.map(function(y, j) {
		          var n = i * 9 + j;
			  return INPUT({type:'text', id: 'inp' + n, name: n, value:y, size: 1,
                                        onfocus: 'Field.clear(inp' + n + ')'})}),
		  BR()]}),
	BUTTON({type:'button', onclick: 'button_click()'}, 'solve')]));
}

window.onload = main;
// ]]>
</script>
</head>
<body>
<div id="inputproblem"></div>
<div id="main"></div>
</body>
</html>
